"""
设备管理器
Device Manager

管理所有IoT设备的生命周期和状态
Manages the lifecycle and status of all IoT devices
"""

import logging
import asyncio
import threading
from typing import Dict, Any, Optional, List
from datetime import datetime, timedelta

from ..devices import DeviceFactory
from ..interfaces.device_interface import DeviceInterface

logger = logging.getLogger(__name__)


class DeviceManager:
    """
    设备管理器
    Device Manager
    
    负责管理所有IoT设备的注册、状态监控和生命周期
    Responsible for managing registration, status monitoring, and lifecycle of all IoT devices
    """
    
    _instance = None
    _lock = threading.Lock()
    
    def __new__(cls):
        """线程安全的单例模式 / Thread-safe singleton pattern"""
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
        return cls._instance
    
    def __init__(self):
        """初始化设备管理器 / Initialize device manager"""
        # 避免重复初始化 / Avoid duplicate initialization
        if hasattr(self, 'initialized'):
            return
            
        self.devices: Dict[str, DeviceInterface] = {}  # 设备实例字典 / Device instance dictionary
        self.device_types: Dict[str, str] = {}  # 设备类型映射 / Device type mapping
        self.device_last_seen: Dict[str, datetime] = {}  # 设备最后在线时间 / Device last seen time
        self.offline_threshold = timedelta(minutes=10)  # 离线阈值 / Offline threshold
        self.max_devices = 10000  # 最大设备数量限制 / Maximum device count limit
        self.cleanup_threshold = timedelta(hours=24)  # 清理阈值 / Cleanup threshold
        self.logger = logging.getLogger(f"{self.__class__.__name__}")
        
        # 监控任务相关 / Monitoring task related
        self._monitoring_task = None
        self._monitoring_enabled = True
        self._restart_count = 0
        self._max_restart_count = 5
        self._monitoring_started = False
        
        self.initialized = True
    
    async def start_monitoring(self):
        """启动设备监控任务 / Start device monitoring task"""
        if not self._monitoring_enabled or self._monitoring_started:
            return

        try:
            if self._monitoring_task is None or self._monitoring_task.done():
                self._monitoring_task = asyncio.create_task(self._monitor_devices())
                # 添加异常回调 / Add exception callback
                self._monitoring_task.add_done_callback(self._on_monitoring_task_done)
                self._monitoring_started = True
                self.logger.info("设备监控任务已启动 / Device monitoring task started")
        except Exception as e:
            self.logger.error(f"启动监控任务失败 / Failed to start monitoring task: {str(e)}")
    
    def _start_monitoring(self):
        """内部启动监控任务方法 / Internal start monitoring method"""
        if not self._monitoring_enabled:
            return

        try:
            # 尝试获取当前事件循环 / Try to get current event loop
            loop = asyncio.get_running_loop()
            if self._monitoring_task is None or self._monitoring_task.done():
                self._monitoring_task = asyncio.create_task(self._monitor_devices())
                # 添加异常回调 / Add exception callback
                self._monitoring_task.add_done_callback(self._on_monitoring_task_done)
                self._monitoring_started = True
                self.logger.info("设备监控任务已启动 / Device monitoring task started")
        except RuntimeError:
            # 没有运行的事件循环，延迟启动 / No running event loop, delay start
            self.logger.info("暂无事件循环，监控任务将在稍后启动 / No event loop available, monitoring will start later")
        except Exception as e:
            self.logger.error(f"启动监控任务失败 / Failed to start monitoring task: {str(e)}")
    
    def _on_monitoring_task_done(self, task):
        """监控任务完成回调 / Monitoring task completion callback"""
        try:
            if task.exception() and self._monitoring_enabled:
                self._restart_count += 1
                self.logger.error(
                    f"监控任务异常退出 / Monitoring task exited with exception: {task.exception()}, "
                    f"重启次数 / Restart count: {self._restart_count}"
                )
                
                # 检查是否超过最大重启次数 / Check if max restart count exceeded
                if self._restart_count < self._max_restart_count:
                    # 延迟重启，避免频繁重启 / Delay restart to avoid frequent restarts
                    try:
                        asyncio.create_task(self._delayed_restart())
                    except RuntimeError:
                        # 如果没有事件循环，标记需要重启 / If no event loop, mark for restart
                        self._monitoring_started = False
                else:
                    self.logger.critical(
                        f"监控任务重启次数过多，停止重启 / "
                        f"Too many monitoring task restarts, stopping restart attempts"
                    )
                    self._monitoring_enabled = False
        except Exception as e:
            self.logger.error(f"处理监控任务回调失败 / Failed to handle monitoring task callback: {str(e)}")
    
    async def _delayed_restart(self):
        """延迟重启监控任务 / Delayed restart of monitoring task"""
        try:
            # 延迟时间递增 / Increasing delay time
            delay = min(60, 5 * self._restart_count)
            await asyncio.sleep(delay)
            
            if self._monitoring_enabled:
                try:
                    await self.start_monitoring()
                except Exception as e:
                    self.logger.error(f"重启监控任务失败 / Failed to restart monitoring: {str(e)}")
                    self._start_monitoring()  # 回退到同步方法 / Fallback to sync method
        except Exception as e:
            self.logger.error(f"延迟重启失败 / Delayed restart failed: {str(e)}")
    
    async def _monitor_devices(self):
        """设备状态监控循环 / Device status monitoring loop"""
        while True:
            try:
                await self._check_device_status()
                await asyncio.sleep(60)  # 每分钟检查一次 / Check every minute
            except asyncio.CancelledError:
                self.logger.info("设备监控任务已停止 / Device monitoring task stopped")
                break
            except Exception as e:
                self.logger.error(f"设备监控任务异常 / Device monitoring task error: {str(e)}")
                await asyncio.sleep(60)
    
    async def _check_device_status(self):
        """检查设备状态 / Check device status"""
        try:
            current_time = datetime.now()
            offline_devices = []
            devices_to_cleanup = []
            
            # 检查设备状态 / Check device status
            for device_id, last_seen in list(self.device_last_seen.items()):
                try:
                    time_diff = current_time - last_seen
                    
                    # 检查是否离线 / Check if offline
                    if time_diff > self.offline_threshold:
                        device = self.devices.get(device_id)
                        if device and device.is_online:
                            await device.update_online_status(False)
                            offline_devices.append(device_id)
                    
                    # 检查是否需要清理 / Check if cleanup needed
                    if time_diff > self.cleanup_threshold:
                        devices_to_cleanup.append(device_id)
                        
                except Exception as device_error:
                    self.logger.error(f"检查设备{device_id}状态失败 / Failed to check device {device_id} status: {str(device_error)}")
            
            # 批量清理过期设备 / Batch cleanup expired devices
            if devices_to_cleanup:
                self.logger.info(f"清理过期设备 / Cleaning up expired devices: {len(devices_to_cleanup)}")
                for device_id in devices_to_cleanup:
                    try:
                        await self.unregister_device(device_id)
                    except Exception as cleanup_error:
                        self.logger.error(f"清理设备{device_id}失败 / Failed to cleanup device {device_id}: {str(cleanup_error)}")
            
            # 记录离线设备 / Log offline devices
            if offline_devices:
                self.logger.warning(f"检测到离线设备 / Detected offline devices: {len(offline_devices)} devices")
                
            # 检查设备数量限制 / Check device count limit
            if len(self.devices) > self.max_devices:
                self.logger.warning(
                    f"设备数量超过限制 / Device count exceeds limit: {len(self.devices)}/{self.max_devices}"
                )
        
        except Exception as e:
            self.logger.error(f"检查设备状态时发生错误 / Error checking device status: {str(e)}")
    
    async def ensure_monitoring_started(self):
        """确保监控已启动 / Ensure monitoring is started"""
        if not self._monitoring_started and self._monitoring_enabled:
            await self.start_monitoring()
    
    async def register_device(self, device_id: str, device_type: str) -> DeviceInterface:
        """
        注册设备
        Register device
        
        Args:
            device_id (str): 设备ID / Device ID
            device_type (str): 设备类型 / Device type
            
        Returns:
            DeviceInterface: 设备实例 / Device instance
            
        Raises:
            ValueError: 设备类型不支持或参数无效 / Unsupported device type or invalid parameters
            RuntimeError: 设备数量超过限制 / Device count exceeds limit
        """
        try:
            # 确保监控已启动 / Ensure monitoring is started
            await self.ensure_monitoring_started()
            
            # 参数验证 / Parameter validation
            if not device_id or not isinstance(device_id, str):
                raise ValueError("设备ID不能为空且必须是字符串 / Device ID cannot be empty and must be a string")
                
            if not device_type or not isinstance(device_type, str):
                raise ValueError("设备类型不能为空且必须是字符串 / Device type cannot be empty and must be a string")
            
            device_id = device_id.strip()
            device_type = device_type.strip().upper()
            
            # 检查设备数量限制 / Check device count limit
            if len(self.devices) >= self.max_devices:
                raise RuntimeError(
                    f"设备数量已达到上限 / Device count has reached the limit: {self.max_devices}"
                )
            
            # 检查设备是否已注册 / Check if device is already registered
            if device_id in self.devices:
                existing_device = self.devices[device_id]
                # 更新最后见时间 / Update last seen time
                self.device_last_seen[device_id] = datetime.now()
                self.logger.info(f"设备已存在，返回现有实例 / Device already exists, returning existing instance: {device_id}")
                return existing_device
            
            # 创建设备实例 / Create device instance
            try:
                device = DeviceFactory.create_device(device_type, device_id)
            except Exception as factory_error:
                raise ValueError(f"创建设备实例失败 / Failed to create device instance: {str(factory_error)}")
            
            # 注册设备 / Register device
            self.devices[device_id] = device
            self.device_types[device_id] = device_type
            self.device_last_seen[device_id] = datetime.now()
            
            self.logger.info(
                f"设备注册成功 / Device registered successfully: {device_id} ({device_type}), "
                f"当前设备数量 / Current device count: {len(self.devices)}"
            )
            return device
            
        except (ValueError, RuntimeError):
            # 重新抛出预期的异常 / Re-raise expected exceptions
            raise
        except Exception as e:
            self.logger.error(f"注册设备失败 / Device registration failed: {device_id}, {str(e)}")
            raise RuntimeError(f"设备注册内部错误 / Internal device registration error: {str(e)}")
    
    async def unregister_device(self, device_id: str) -> bool:
        """
        注销设备
        Unregister device
        
        Args:
            device_id (str): 设备ID / Device ID
            
        Returns:
            bool: 注销是否成功 / Whether unregistration was successful
        """
        try:
            if device_id in self.devices:
                del self.devices[device_id]
                del self.device_types[device_id]
                if device_id in self.device_last_seen:
                    del self.device_last_seen[device_id]
                
                self.logger.info(f"设备注销成功 / Device unregistered successfully: {device_id}")
                return True
            else:
                self.logger.warning(f"设备不存在，无法注销 / Device does not exist, cannot unregister: {device_id}")
                return False
                
        except Exception as e:
            self.logger.error(f"注销设备失败 / Device unregistration failed: {device_id}, {str(e)}")
            return False
    
    def get_device(self, device_id: str) -> Optional[DeviceInterface]:
        """
        获取设备实例
        Get device instance
        
        Args:
            device_id (str): 设备ID / Device ID
            
        Returns:
            Optional[DeviceInterface]: 设备实例 / Device instance
        """
        device = self.devices.get(device_id)
        if device:
            # 更新最后在线时间 / Update last seen time
            self.device_last_seen[device_id] = datetime.now()
        return device
    
    async def update_device_status(self, device_id: str, is_online: bool = True) -> bool:
        """
        更新设备状态
        Update device status
        
        Args:
            device_id (str): 设备ID / Device ID
            is_online (bool): 是否在线 / Whether online
            
        Returns:
            bool: 更新是否成功 / Whether update was successful
        """
        try:
            device = self.devices.get(device_id)
            if device:
                await device.update_online_status(is_online)
                if is_online:
                    self.device_last_seen[device_id] = datetime.now()
                return True
            else:
                self.logger.warning(f"设备不存在，无法更新状态 / Device does not exist, cannot update status: {device_id}")
                return False
                
        except Exception as e:
            self.logger.error(f"更新设备状态失败 / Device status update failed: {device_id}, {str(e)}")
            return False
    
    def get_all_devices(self) -> Dict[str, DeviceInterface]:
        """
        获取所有设备
        Get all devices
        
        Returns:
            Dict[str, DeviceInterface]: 所有设备字典 / All devices dictionary
        """
        return self.devices.copy()
    
    def get_devices_by_type(self, device_type: str) -> List[DeviceInterface]:
        """
        根据类型获取设备列表
        Get devices by type
        
        Args:
            device_type (str): 设备类型 / Device type
            
        Returns:
            List[DeviceInterface]: 设备列表 / Device list
        """
        return [
            device for device_id, device in self.devices.items()
            if self.device_types.get(device_id) == device_type
        ]
    
    def get_online_devices(self) -> List[DeviceInterface]:
        """
        获取在线设备列表
        Get online devices
        
        Returns:
            List[DeviceInterface]: 在线设备列表 / Online device list
        """
        return [device for device in self.devices.values() if device.is_online]
    
    def get_offline_devices(self) -> List[DeviceInterface]:
        """
        获取离线设备列表
        Get offline devices
        
        Returns:
            List[DeviceInterface]: 离线设备列表 / Offline device list
        """
        return [device for device in self.devices.values() if not device.is_online]
    
    async def get_device_statistics(self) -> Dict[str, Any]:
        """
        获取设备统计信息
        Get device statistics
        
        Returns:
            Dict[str, Any]: 统计信息 / Statistics information
        """
        try:
            total_devices = len(self.devices)
            online_devices = len(self.get_online_devices())
            offline_devices = len(self.get_offline_devices())
            
            # 按设备类型统计 / Statistics by device type
            type_stats = {}
            for device_type in set(self.device_types.values()):
                devices_of_type = self.get_devices_by_type(device_type)
                online_of_type = len([d for d in devices_of_type if d.is_online])
                type_stats[device_type] = {
                    'total': len(devices_of_type),
                    'online': online_of_type,
                    'offline': len(devices_of_type) - online_of_type
                }
            
            return {
                'total_devices': total_devices,
                'online_devices': online_devices,
                'offline_devices': offline_devices,
                'online_rate': round(online_devices / total_devices * 100, 2) if total_devices > 0 else 0,
                'device_types': list(set(self.device_types.values())),
                'type_statistics': type_stats,
                'last_updated': datetime.now().isoformat()
            }
            
        except Exception as e:
            self.logger.error(f"获取设备统计信息失败 / Failed to get device statistics: {str(e)}")
            return {}
    
    async def batch_health_check(self, device_ids: Optional[List[str]] = None) -> Dict[str, Dict[str, Any]]:
        """
        批量设备健康检查
        Batch device health check
        
        Args:
            device_ids (Optional[List[str]]): 设备ID列表，为空则检查所有设备 / Device ID list, check all if empty
            
        Returns:
            Dict[str, Dict[str, Any]]: 健康检查结果 / Health check results
        """
        try:
            if device_ids is None:
                device_ids = list(self.devices.keys())
            
            health_results = {}
            
            for device_id in device_ids:
                device = self.devices.get(device_id)
                if device:
                    try:
                        health_status = await device.health_check()
                        health_results[device_id] = health_status
                    except Exception as e:
                        health_results[device_id] = {
                            'status': 'error',
                            'error': str(e),
                            'device_id': device_id
                        }
                else:
                    health_results[device_id] = {
                        'status': 'not_found',
                        'error': '设备未找到 / Device not found',
                        'device_id': device_id
                    }
            
            return health_results
            
        except Exception as e:
            self.logger.error(f"批量健康检查失败 / Batch health check failed: {str(e)}")
            return {}
    
    async def cleanup(self):
        """清理资源 / Cleanup resources"""
        try:
            self.logger.info("开始清理设备管理器资源 / Starting device manager cleanup")
            
            # 停止监控 / Stop monitoring
            self._monitoring_enabled = False
            
            # 取消监控任务 / Cancel monitoring task
            if self._monitoring_task and not self._monitoring_task.done():
                self._monitoring_task.cancel()
                try:
                    await asyncio.wait_for(self._monitoring_task, timeout=5.0)
                except (asyncio.CancelledError, asyncio.TimeoutError):
                    self.logger.warning("监控任务取消超时 / Monitoring task cancellation timeout")
                except Exception as e:
                    self.logger.error(f"取消监控任务失败 / Failed to cancel monitoring task: {str(e)}")
            
            # 清理设备实例 / Cleanup device instances
            device_count = len(self.devices)
            try:
                for device_id, device in list(self.devices.items()):
                    try:
                        # 调用设备的清理方法（如果有）/ Call device cleanup method (if available)
                        if hasattr(device, 'cleanup'):
                            await device.cleanup()
                    except Exception as device_error:
                        self.logger.error(f"清理设备{device_id}失败 / Failed to cleanup device {device_id}: {str(device_error)}")
            except Exception as e:
                self.logger.error(f"清理设备实例失败 / Failed to cleanup device instances: {str(e)}")
            
            # 清空数据结构 / Clear data structures
            self.devices.clear()
            self.device_types.clear()
            self.device_last_seen.clear()
            
            # 重置重启计数器 / Reset restart counter
            self._restart_count = 0
            
            self.logger.info(
                f"设备管理器已清理 / Device manager cleaned up, "
                f"已清理设备数量 / Cleaned up device count: {device_count}"
            )
            
        except Exception as e:
            self.logger.error(f"清理设备管理器失败 / Failed to cleanup device manager: {str(e)}")
            # 即使清理失败也要尽可能清空数据 / Clear data even if cleanup fails
            try:
                self.devices.clear()
                self.device_types.clear()
                self.device_last_seen.clear()
            except:
                pass


# 全局设备管理器实例（使用单例模式）/ Global device manager instance (using singleton pattern)
device_manager = DeviceManager()